<html>  
<head>  
  <link rel="stylesheet" href="qunit/qunit.css" type="text/css"/>  
  <script src="../editor/jquery.js"></script>  
  <script type="text/javascript" src="../editor/svgicons/jquery.svgicons.js"></script>
  <script type="text/javascript" src="../editor/locale/locale.js"></script>
  <script type="text/javascript" src="../editor/svgcanvas.js"></script>
  <script type="text/javascript" src="qunit/qunit.js"></script>  
  <script type="text/javascript">
  $(function() {
  	// log function
  	QUnit.log = function(result, message) {
		if (window.console && window.console.log) {
			window.console.log(result +' :: '+ message);
		}
	};
	
	// helper functions
	var isIdentity = function(m) {
		return (m.a == 1 && m.b == 0 && m.c == 0 && m.d == 1 && m.e == 0 && m.f == 0);
	};
	var matrixString = function(m) {
		return [m.a,m.b,m.c,m.d,m.e,m.f].join(',');
	}

  	var svgCanvas = new $.SvgCanvas(document.getElementById("svgcanvas"), {
			canvas_expansion: 3,
			dimensions: [640,480],
			initFill: {
				color: 'FF0000',  // solid red
				opacity: 1
			},
			initStroke: {
				width: 5,
				color: '000000',  // solid black
				opacity: 1
			},
			initOpacity: 1,
			imgPath: 'images/',
			langPath: 'locale/',
			extPath: 'extensions/',
			extensions: ['ext-arrows.js', 'ext-connector.js', 'ext-eyedropper.js'],
			initTool: 'select',
			wireframe: false
		}),
  		svgroot = document.getElementById("svgroot"),
  		svgdoc = svgroot.documentElement,
  		svgns = "http://www.w3.org/2000/svg",
  		xlinkns = "http://www.w3.org/1999/xlink";

	module("Basic Module");

	test("Test existence of SvgCanvas object", function() {
		expect(1);
		equal(typeof {}, typeof svgCanvas);
	});
	
	module("Path Module");
	
	test("Test path conversion from absolute to relative", function() {
		expect(6);
		var convert = svgCanvas.pathActions.convertPath;

		// TODO: Test these paths:
		// "m400.00491,625.01379a1.78688,1.78688 0 1 1-3.57373,0a1.78688,1.78688 0 1 13.57373,0z"
		// "m36.812,15.8566c-28.03099,0 -26.28099,12.15601 -26.28099,12.15601l0.03099,12.59399h26.75v3.781h-37.37399c0,0 -17.938,-2.034 -133.00001,26.25c115.06201,28.284 130.71801,27.281 130.71801,27.281h9.34399v-13.125c0,0 -0.504,-15.656 15.40601,-15.656h26.532c0,0 14.90599,0.241 14.90599,-14.406v-24.219c0,0 2.263,-14.65601 -27.032,-14.65601zm-14.75,8.4684c2.662,0 4.813,2.151 4.813,4.813c0,2.661 -2.151,4.812 -4.813,4.812c-2.661,0 -4.812,-2.151 -4.812,-4.812c0,-2.662 2.151,-4.813 4.812,-4.813z"
		// "m 0,0 l 200,0 l 0,100 L 0,100"
	
		svgCanvas.setSvgString("<svg xmlns='http://www.w3.org/2000/svg' width='400' x='300'>" +
								  "<path id='p1' d='M100,100 L200,100 Z'/>" +
								  "<path id='p2' d='m 0,0 l 200,0 l 0,100 L 0,100'/>" +
								"</svg>");
		
		var p1 = document.getElementById("p1"),
			p2 = document.getElementById("p2"),
			d_abs = p1.getAttribute("d"),
			seglist = p1.pathSegList,
			curseg = null;
			
		equal(p1.nodeName, "path", "Expected 'path', got");
		
		equal(seglist.numberOfItems, 3, "Number of segments before conversion");
		
		// verify segments before conversion
		curseg = seglist.getItem(0);
		equal(curseg.pathSegTypeAsLetter, "M", "Before conversion, segment #1 type");
		curseg = seglist.getItem(1);
		equal(curseg.pathSegTypeAsLetter, "L", "Before conversion, segment #2 type");
		curseg = seglist.getItem(2);
		equal(curseg.pathSegType, 1, "Before conversion, segment #3 type");
		
		// convert and verify segments
		var d = convert(p1, true);
		equal(d, "m100,100l100,0z", "Converted path to relative string");
		
		// TODO: see why this isn't working in SVG-edit
		d = convert(p2, true);
		QUnit.log(d);
		d = convert(p2, false);
		QUnit.log(d);
	});
	
	module("Transform Module");

	test("Test matrixMultiply", function() {
		expect(5);

		// translate there and back
		var tr_1 = svgroot.createSVGMatrix().translate(100,50),
			tr_2 = svgroot.createSVGMatrix().translate(-90,0),
			tr_3 = svgroot.createSVGMatrix().translate(-10,-50),
			I = svgCanvas.matrixMultiply(tr_1,tr_2,tr_3);
		equal(isIdentity(I), true,
			"Expected identity matrix when translating there and back, got " + matrixString(I));

		// rotate there and back
		// TODO: currently Mozilla fails this when rotating back at -50 and then -40 degrees
		// (b and c are *almost* zero, but not zero)
		var rot_there = svgroot.createSVGMatrix().rotate(90),
			rot_back = svgroot.createSVGMatrix().rotate(-90); // TODO: set this to -50
			rot_back_more = svgroot.createSVGMatrix().rotate(0); // TODO: set this to -40
		I = svgCanvas.matrixMultiply(rot_there, rot_back, rot_back_more);
		equal(isIdentity(I), true,
			"Expected identity matrix when rotating there and back, got " + matrixString(I));

		// scale up and down
		var scale_up = svgroot.createSVGMatrix().scale(4),
			scale_down = svgroot.createSVGMatrix().scaleNonUniform(0.25,1);
			scale_down_more = svgroot.createSVGMatrix().scaleNonUniform(1,0.25);
		I = svgCanvas.matrixMultiply(scale_up, scale_down, scale_down_more);
		equal(isIdentity(I), true,
			"Expected identity matrix when scaling up and down, got " + matrixString(I));

		// test multiplication with its inverse 
		I = svgCanvas.matrixMultiply(rot_there, rot_there.inverse());
		equal(isIdentity(I), true,
			"Expected identity matrix when multiplying a matrix by its inverse, got " + matrixString(I));
		I = svgCanvas.matrixMultiply(rot_there.inverse(), rot_there);
		equal(isIdentity(I), true,
			"Expected identity matrix when multiplying a matrix by its inverse, got " + matrixString(I));
	});
	
	module("Import Module");
	
	test("Test import use", function() {
		expect(3);
		
		svgCanvas.setSvgString("<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='400' x='300'>" +
								"<rect id='the-rect' width='200' height='200'/>" +
								"<use id='the-use' xlink:href='#the-rect'/>" +
								"<use id='foreign-use' xlink:href='somefile.svg#the-rect'/>" +
								"<use id='no-use'/>" +
								"</svg>");
		
		var u = document.getElementById("the-use"),
			fu = document.getElementById("foreign-use"),
			nfu = document.getElementById("no-use");
		
		equal((u && u.nodeName == "use"), true, "Did not import <use> element");
		equal(fu, null, "Removed <use> element that had a foreign href");
		equal(nfu, null, "Removed <use> element that had no href");
	});
	
	test("Test getUrlFromAttr", function() {
		expect(4);
		
		equal(svgCanvas.getUrlFromAttr("url(#foo)"), "#foo");
		equal(svgCanvas.getUrlFromAttr("url(somefile.svg#foo)"), "somefile.svg#foo");
		equal(svgCanvas.getUrlFromAttr("url('#foo')"), "#foo");
		equal(svgCanvas.getUrlFromAttr('url("#foo")'), "#foo");
	});
	
	// This test shows that an element with an invalid attribute is still parsed in properly
	// and only the attribute is not imported
	test("Test invalid attribute", function() {
		expect(2);
		
		svgCanvas.setSvgString('<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg">'+
				'<text x="182.75" y="173.5" id="the-text" fill="#008000" font-size="150" font-family="serif" text-anchor="middle" d="M116,222 L110,108">words</text>' +
				'</svg>');
		
		var t = document.getElementById("the-text");
		
		equal(true, (t && t.nodeName == "text"), "Did not import <text> element");
		equal(null, t.getAttribute("d"), "Imported a <text> with a d attribute");
	});
	
	// This test makes sure import/export properly handles namespaced attributes
	test("Test importing/exporting namespaced attributes", function() {
		expect(5);
		var set = svgCanvas.setSvgString('<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:se="http://svg-edit.googlecode.com" xmlns:foo="http://example.com">'+
				'<image xlink:href="../editor/images/logo.png"/>' +
				'<polyline id="se_test_elem" se:foo="bar"/>' +
				'</svg>');
		var attrVal = document.getElementById('se_test_elem').getAttributeNS("http://svg-edit.googlecode.com", "foo");
		
		equal(attrVal === "bar", true, "Preserved namespaced attribute on import");
				
		var output = svgCanvas.getSvgString();
		var has_xlink = output.indexOf('xmlns:xlink="http://www.w3.org/1999/xlink"') !== -1;
		var has_se = output.indexOf('xmlns:se=') !== -1;
		var has_foo = output.indexOf('xmlns:foo=') !== -1;
		var has_attr = output.indexOf('se:foo="bar"') !== -1;
		
		equal(has_attr, true, "Preserved namespaced attribute on export");
		equal(has_xlink, true, "Included xlink: xmlns");
		equal(has_se, true, "Included se: xmlns");
		equal(has_foo, false, "Did not include foo: xmlns");
	});
	
	test("Test import math elements inside a foreignObject", function() {
		expect(4);
		var set = svgCanvas.setSvgString('<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:se="http://svg-edit.googlecode.com" xmlns:xlink="http://www.w3.org/1999/xlink">'+
				'<foreignObject id="fo" width="24" height="26" font-size="24"><math id="m" display="inline" xmlns="http://www.w3.org/1998/Math/MathML">'+
						'<msub>'+
							'<mi>A</mi>'+
							'<mn>0</mn>'+
						'</msub>'+
					'</math>'+
				'</foreignObject>'+
			'</svg>');
		var fo = document.getElementById('fo');
		// we cannot use getElementById('math') because not all browsers understand MathML and do not know to use the @id attribute
		// see Bug https://bugs.webkit.org/show_bug.cgi?id=35042
		var math = fo.firstChild;
		
		equal(!!math, true, "Math element exists");
		equal(math.nodeName, 'math', "Math element has the proper nodeName");
		equal(math.getAttribute('id'), 'm', "Math element has an id");
		equal(math.namespaceURI, "http://www.w3.org/1998/Math/MathML", "Preserved MathML namespace");
	});
	
	test("Test escaping XML entities", function() {
		expect(3);
		
		equal(svgCanvas.getPrivateMethods().toXml("<"), "&lt;", "Escaped < properly");
		equal(svgCanvas.getPrivateMethods().toXml(">"), "&gt;", "Escaped > properly");
		equal(svgCanvas.getPrivateMethods().toXml("&"), "&amp;", "Escaped & properly");
		// TODO: what about &quot; and &apos; ?
	});
	
	test("Test importing SVG into existing drawing", function() {
		expect(3);
		
		var doc = svgCanvas.setSvgString('<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg">'+
											'<g><title>Layer 1</title>'+
												'<circle cx="200" cy="200" r="50" fill="blue"/>'+
												'<ellipse cx="300" cy="100" rx="40" ry="30" fill="green"/>'+
											'</g>'+
										'</svg>');
		
		svgCanvas.importSvgString('<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">'+
									'<circle cx="50" cy="50" r="40" fill="yellow"/>'+
									'<rect width="20" height="20" fill="blue"/>'+
								'</svg>');
		
		var svgcontent = document.getElementById("svgcontent"),
			circles = svgcontent.getElementsByTagNameNS(svgns, "circle"),
			rects = svgcontent.getElementsByTagNameNS(svgns, "rect"),
			ellipses = svgcontent.getElementsByTagNameNS(svgns, "ellipse");
		equal(circles.length, 2, "Found two circles upon importing");
		equal(rects.length, 1, "Found one rectangle upon importing");
		equal(ellipses.length, 1, "Found one ellipse upon importing");
	});

	test("Test importing SVG remaps IDs", function() {
		expect(6);
		
		var doc = svgCanvas.setSvgString('<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg">'+
											'<g><title>Layer 1</title>'+
												'<ellipse id="svg_1" cx="200" cy="200" rx="50" ry="20" fill="blue"/>'+
												'<ellipse id="svg_2" cx="300" cy="100" rx="40" ry="30" fill="green"/>'+
												'<ellipse id="svg_3" cx="300" cy="100" rx="40" ry="30" fill="green"/>'+
											'</g>'+
										'</svg>');
		
		svgCanvas.importSvgString('<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink">'+
									'<defs>'+
										'<linearGradient id="svg_2">'+
											'<stop stop-color="red" offset="0"/>'+
											'<stop stop-color="green" offset="1"/>'+
										'</linearGradient>'+
										'<rect id="svg_3" width="20" height="20" fill="blue" stroke="url(#svg_2)"/>'+
									'</defs>'+
									'<circle id="svg_1" cx="50" cy="50" r="40" fill="url(#svg_2)"/>'+
									'<use id="svg_4" width="30" height="30" xl:href="#svg_3"/>'+
								'</svg>');
		
		var svgcontent = document.getElementById("svgcontent"),
			circles = svgcontent.getElementsByTagNameNS(svgns, "circle"),
			rects = svgcontent.getElementsByTagNameNS(svgns, "rect"),
			ellipses = svgcontent.getElementsByTagNameNS(svgns, "ellipse"),
			defs = svgcontent.getElementsByTagNameNS(svgns, "defs"),
			grads = svgcontent.getElementsByTagNameNS(svgns, "linearGradient"),
			uses = svgcontent.getElementsByTagNameNS(svgns, "use");
		notEqual(circles.item(0).id, "svg_1", "Circle not re-identified");
		notEqual(rects.item(0).id, "svg_3", "Rectangle not re-identified");
//		// TODO: determine why this test fails in WebKit browsers
//		equal(grads.length, 1, "Linear gradient imported");
		var grad = defs.item(0).firstChild;
		notEqual(grad.id, "svg_2", "Linear gradient not re-identified");
		notEqual(circles.item(0).getAttribute("fill"), "url(#svg_2)", "Circle fill value not remapped");
		notEqual(rects.item(0).getAttribute("stroke"), "url(#svg_2)", "Rectangle stroke value not remapped");
		notEqual(uses.item(0).getAttributeNS(xlinkns, "href"), "#svg_3");
	});
	
  }); 
  </script>  
</head>  
<body>  
  <h1 id="qunit-header">Unit Tests for SvgCanvas</h1>
  <h2 id="qunit-banner"></h2>
  <h2 id="qunit-userAgent"></h2>
  <ol id="qunit-tests">
  </ol>
  <div id="svgcanvas" style="visibility:hidden"></div>
</body>  
</html> 